using AgentFrameworkDemo.Models;
using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;

namespace AgentFrameworkDemo.Services;

/// <summary>
/// 简化的工具管理器实现
/// </summary>
public class ToolManager : IToolManager
{
    private readonly ConcurrentDictionary<string, ITool> _tools = new();
    private readonly ILogger<ToolManager> _logger;

    public ToolManager(ILogger<ToolManager> logger)
    {
        _logger = logger;

        // 注册默认工具
        RegisterDefaultTools();

        _logger.LogInformation("ToolManager initialized with {Count} tools", _tools.Count);
    }

    private void RegisterDefaultTools()
    {
        // 注册基础工具
        RegisterToolAsync(new DateTimeTool()).Wait();
        RegisterToolAsync(new TextTool()).Wait();
        RegisterToolAsync(new MathTool()).Wait();
        RegisterToolAsync(new WeatherTool()).Wait();
    }

    public async Task RegisterToolAsync(ITool tool)
    {
        try
        {
            _tools[tool.Id] = tool;
            _logger.LogDebug("Tool registered: {ToolId} - {ToolName}", tool.Id, tool.Name);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to register tool: {ToolId}", tool.Id);
            throw;
        }

        await Task.CompletedTask;
    }

    public async Task<ITool?> GetToolAsync(string toolId)
    {
        _logger.LogDebug("Getting tool: {ToolId}", toolId);

        if (_tools.TryGetValue(toolId, out var tool))
        {
            await Task.CompletedTask;
            return tool;
        }

        return null;
    }

    public async Task<ToolResult> ExecuteToolAsync(string toolId, ToolParameters parameters)
    {
        _logger.LogInformation("Executing tool: {ToolId}", toolId);

        if (!_tools.TryGetValue(toolId, out var tool))
        {
            return new ToolResult
            {
                ToolId = toolId,
                ToolName = toolId,
                Success = false,
                ErrorMessage = $"Tool not found: {toolId}",
                ExecutionTime = TimeSpan.Zero
            };
        }

        var startTime = DateTime.UtcNow;

        try
        {
            var result = await tool.ExecuteAsync(parameters);

            var executionTime = DateTime.UtcNow - startTime;
            result.ExecutionTime = executionTime;

            _logger.LogInformation("Tool executed successfully: {ToolId}, Duration: {Duration}ms",
                toolId, executionTime.TotalMilliseconds);

            return result;
        }
        catch (Exception ex)
        {
            var executionTime = DateTime.UtcNow - startTime;

            _logger.LogError(ex, "Tool execution failed: {ToolId}", toolId);

            return new ToolResult
            {
                ToolId = toolId,
                ToolName = tool.Name,
                Success = false,
                ErrorMessage = ex.Message,
                ExecutionTime = executionTime
            };
        }
    }

    public async Task<List<ITool>> ListToolsAsync()
    {
        await Task.CompletedTask;
        return _tools.Values.ToList();
    }

    public async Task UnregisterToolAsync(string toolId)
    {
        try
        {
            if (_tools.TryRemove(toolId, out _))
            {
                _logger.LogDebug("Tool unregistered: {ToolId}", toolId);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to unregister tool: {ToolId}", toolId);
        }

        await Task.CompletedTask;
    }
}

/// <summary>
/// 日期时间工具
/// </summary>
public class DateTimeTool : ITool
{
    public string Id => "datetime";
    public string Name => "日期时间工具";
    public string Description => "获取当前日期时间信息";
    public List<ToolParameter> Parameters => new();

    public async Task<ToolResult> ExecuteAsync(ToolParameters parameters)
    {
        var now = DateTime.UtcNow;
        var result = new Dictionary<string, object>
        {
            ["current_time"] = now.ToString("yyyy-MM-dd HH:mm:ss"),
            ["date"] = now.ToString("yyyy-MM-dd"),
            ["time"] = now.ToString("HH:mm:ss"),
            ["timestamp"] = ((DateTimeOffset)now).ToUnixTimeSeconds(),
            ["day_of_week"] = now.DayOfWeek.ToString(),
            ["year"] = now.Year,
            ["month"] = now.Month,
            ["day"] = now.Day
        };

        return new ToolResult
        {
            ToolId = Id,
            ToolName = Name,
            Success = true,
            Result = result,
            ExecutionTime = TimeSpan.Zero
        };
    }
}

/// <summary>
/// 文本处理工具
/// </summary>
public class TextTool : ITool
{
    public string Id => "text";
    public string Name => "文本处理工具";
    public string Description => "处理文本数据，如长度计算、格式化等";
    public List<ToolParameter> Parameters => new()
    {
        new ToolParameter
        {
            Name = "operation",
            Type = "string",
            Description = "操作类型：length, uppercase, lowercase, reverse",
            Required = true
        },
        new ToolParameter
        {
            Name = "text",
            Type = "string",
            Description = "要处理的文本",
            Required = true
        }
    };

    public async Task<ToolResult> ExecuteAsync(ToolParameters parameters)
    {
        if (!parameters.Values.TryGetValue("operation", out var operationObj) ||
            !parameters.Values.TryGetValue("text", out var textObj))
        {
            return new ToolResult
            {
                ToolId = Id,
                ToolName = Name,
                Success = false,
                ErrorMessage = "Missing required parameters: operation, text",
                ExecutionTime = TimeSpan.Zero
            };
        }

        var operation = operationObj.ToString() ?? string.Empty;
        var text = textObj.ToString() ?? string.Empty;

        string result;
        switch (operation.ToLower())
        {
            case "length":
                result = text.Length.ToString();
                break;
            case "uppercase":
                result = text.ToUpper();
                break;
            case "lowercase":
                result = text.ToLower();
                break;
            case "reverse":
                result = new string(text.Reverse().ToArray());
                break;
            default:
                return new ToolResult
                {
                    ToolId = Id,
                    ToolName = Name,
                    Success = false,
                    ErrorMessage = $"Unknown operation: {operation}",
                    ExecutionTime = TimeSpan.Zero
                };
        }

        return new ToolResult
        {
            ToolId = Id,
            ToolName = Name,
            Success = true,
            Result = result,
            ExecutionTime = TimeSpan.Zero
        };
    }
}

/// <summary>
/// 数学计算工具
/// </summary>
public class MathTool : ITool
{
    public string Id => "math";
    public string Name => "数学计算工具";
    public string Description => "执行基本的数学计算";
    public List<ToolParameter> Parameters => new()
    {
        new ToolParameter
        {
            Name = "operation",
            Type = "string",
            Description = "操作类型：add, subtract, multiply, divide, power",
            Required = true
        },
        new ToolParameter
        {
            Name = "a",
            Type = "number",
            Description = "第一个数字",
            Required = true
        },
        new ToolParameter
        {
            Name = "b",
            Type = "number",
            Description = "第二个数字",
            Required = false
        }
    };

    public async Task<ToolResult> ExecuteAsync(ToolParameters parameters)
    {
        if (!parameters.Values.TryGetValue("operation", out var operationObj) ||
            !parameters.Values.TryGetValue("a", out var aObj))
        {
            return new ToolResult
            {
                ToolId = Id,
                ToolName = Name,
                Success = false,
                ErrorMessage = "Missing required parameters: operation, a",
                ExecutionTime = TimeSpan.Zero
            };
        }

        var operation = operationObj.ToString() ?? string.Empty;

        if (!double.TryParse(aObj.ToString(), out var a))
        {
            return new ToolResult
            {
                ToolId = Id,
                ToolName = Name,
                Success = false,
                ErrorMessage = "Invalid number for parameter 'a'",
                ExecutionTime = TimeSpan.Zero
            };
        }

        double result = 0;

        switch (operation.ToLower())
        {
            case "add":
                if (!parameters.Values.TryGetValue("b", out var bObj) ||
                    !double.TryParse(bObj.ToString(), out var b))
                {
                    return new ToolResult
                    {
                        ToolId = Id,
                        ToolName = Name,
                        Success = false,
                        ErrorMessage = "Missing or invalid parameter 'b' for addition",
                        ExecutionTime = TimeSpan.Zero
                    };
                }
                result = a + b;
                break;
            case "subtract":
                if (!parameters.Values.TryGetValue("b", out var bSubObj) ||
                    !double.TryParse(bSubObj.ToString(), out var bSub))
                {
                    return new ToolResult
                    {
                        ToolId = Id,
                        ToolName = Name,
                        Success = false,
                        ErrorMessage = "Missing or invalid parameter 'b' for subtraction",
                        ExecutionTime = TimeSpan.Zero
                    };
                }
                result = a - bSub;
                break;
            case "multiply":
                if (!parameters.Values.TryGetValue("b", out var bMulObj) ||
                    !double.TryParse(bMulObj.ToString(), out var bMul))
                {
                    return new ToolResult
                    {
                        ToolId = Id,
                        ToolName = Name,
                        Success = false,
                        ErrorMessage = "Missing or invalid parameter 'b' for multiplication",
                        ExecutionTime = TimeSpan.Zero
                    };
                }
                result = a * bMul;
                break;
            case "divide":
                if (!parameters.Values.TryGetValue("b", out var bDivObj) ||
                    !double.TryParse(bDivObj.ToString(), out var bDiv))
                {
                    return new ToolResult
                    {
                        ToolId = Id,
                        ToolName = Name,
                        Success = false,
                        ErrorMessage = "Missing or invalid parameter 'b' for division",
                        ExecutionTime = TimeSpan.Zero
                    };
                }
                if (bDiv == 0)
                {
                    return new ToolResult
                    {
                        ToolId = Id,
                        ToolName = Name,
                        Success = false,
                        ErrorMessage = "Division by zero",
                        ExecutionTime = TimeSpan.Zero
                    };
                }
                result = a / bDiv;
                break;
            case "power":
                if (!parameters.Values.TryGetValue("b", out var bPowObj) ||
                    !double.TryParse(bPowObj.ToString(), out var bPow))
                {
                    return new ToolResult
                    {
                        ToolId = Id,
                        ToolName = Name,
                        Success = false,
                        ErrorMessage = "Missing or invalid parameter 'b' for power",
                        ExecutionTime = TimeSpan.Zero
                    };
                }
                result = Math.Pow(a, bPow);
                break;
            default:
                return new ToolResult
                {
                    ToolId = Id,
                    ToolName = Name,
                    Success = false,
                    ErrorMessage = $"Unknown operation: {operation}",
                    ExecutionTime = TimeSpan.Zero
                };
        }

        return new ToolResult
        {
            ToolId = Id,
            ToolName = Name,
            Success = true,
            Result = result,
            ExecutionTime = TimeSpan.Zero
        };
    }
}

/// <summary>
/// 模拟天气工具
/// </summary>
public class WeatherTool : ITool
{
    public string Id => "weather";
    public string Name => "天气查询工具";
    public string Description => "查询指定城市的天气信息（模拟数据）";
    public List<ToolParameter> Parameters => new()
    {
        new ToolParameter
        {
            Name = "city",
            Type = "string",
            Description = "城市名称",
            Required = true
        }
    };

    public async Task<ToolResult> ExecuteAsync(ToolParameters parameters)
    {
        if (!parameters.Values.TryGetValue("city", out var cityObj))
        {
            return new ToolResult
            {
                ToolId = Id,
                ToolName = Name,
                Success = false,
                ErrorMessage = "Missing required parameter: city",
                ExecutionTime = TimeSpan.Zero
            };
        }

        var city = cityObj.ToString() ?? "未知城市";

        // 模拟天气数据
        var random = new Random();
        var weather = new Dictionary<string, object>
        {
            ["city"] = city,
            ["temperature"] = random.Next(-10, 35),
            ["humidity"] = random.Next(30, 90),
            ["weather"] = new[] { "晴天", "多云", "阴天", "小雨", "中雨" }[random.Next(5)],
            ["wind_speed"] = random.Next(0, 20),
            ["update_time"] = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")
        };

        return new ToolResult
        {
            ToolId = Id,
            ToolName = Name,
            Success = true,
            Result = weather,
            ExecutionTime = TimeSpan.Zero
        };
    }
}